from flask_restful import marshal_with, Resource, abort
from flask_jwt_extended import jwt_required, get_jwt_identity
from .models import Cloth, Cart, Order, COLLAR_CHOICES, BUTTON_CHOICES
from .resources import ClothResource, CartResource, OrderResource


class ChoicesView(Resource):
    @jwt_required
    def get(self):
        return {
            'collar': COLLAR_CHOICES,
            'button': BUTTON_CHOICES
        }


class ClothesView(Resource):
    @marshal_with(ClothResource.fields)
    @jwt_required
    def get(self):
        clothes = Cloth.query.all()
        return clothes

    @marshal_with(ClothResource.fields)
    @jwt_required
    def post(self):
        args = ClothResource.validate_create()
        cloth = Cloth(**args)
        cloth.create()
        return cloth


class ClothView(Resource):
    @marshal_with(ClothResource.fields)
    @jwt_required
    def get(self, cloth_id):
        cloth = Cloth.query.get(cloth_id)
        if not cloth: abort(404, message="Cloth {} doesn't exist".format(cloth_id))
        return cloth


class CartView(Resource):
    def get_object(self, user_id):
        cart = Cart.query.filter_by(user_id=user_id).first()
        if not cart:
            cart = Cart(user_id=user_id)
            cart.create()
        return cart

    @marshal_with(CartResource.fields)
    @jwt_required
    def get(self):
        user_id = get_jwt_identity()
        cart = self.get_object(user_id)
        return cart

    @marshal_with(CartResource.fields)
    @jwt_required
    def patch(self):
        user_id = get_jwt_identity()
        args = CartResource.validate_update()
        cart = self.get_object(user_id)
        cart.clothes.clear()
        for cloth_id in args.cloth_ids or []:
            cloth = Cloth.query.get(cloth_id)
            if cloth: cart.clothes.append(cloth)
        cart.update()
        return cart


class OrdersView(Resource):
    @marshal_with(OrderResource.fields)
    @jwt_required
    def get(self):
        user_id = get_jwt_identity()
        orders = Order.query.filter_by(user_id=user_id).all()
        return orders

    @marshal_with(OrderResource.fields)
    @jwt_required
    def post(self):
        user_id = get_jwt_identity()
        order = Order(user_id=user_id)
        order.create()
        args = OrderResource.validate_create()
        for cloth_id in args.cloth_ids or []:
            cloth = Cloth.query.get(cloth_id)
            if cloth: order.clothes.append(cloth)
        order.update()
        return order


class OrderView(Resource):
    @marshal_with(OrderResource.fields)
    def get(self, order_id):
        user_id = get_jwt_identity()
        order = Order.query.filter_by(user_id=user_id, id=order_id).first()
        if not order: abort(404, message="Order {} doesn't exist with User {}".format(user_id, order_id))
        return order

    @marshal_with(OrderResource.fields)
    def patch(self, order_id):
        user_id = get_jwt_identity()
        order = Order.query.filter_by(user_id=user_id, id=order_id).first()
        if not order: abort(404, message="Order {} doesn't exist with User {}".format(user_id, order_id))
        if order.is_placed: abort(404, message="Order {} is placed, cannot update".format(order_id))
        args = OrderResource.validate_update()
        for cloth_id in args.cloth_ids or []:
            cloth = Cloth.query.get(cloth_id)
            if cloth: order.clothes.append(cloth)
        order.update()
        return order

    def delete(self, order_id):
        user_id = get_jwt_identity()
        order = Order.query.filter_by(user_id=user_id, id=order_id).first()
        if not order: abort(404, message="Order {} doesn't exist with User {}".format(user_id, order_id))
        if order.is_placed: abort(404, message="Order {} is placed, cannot cancel or delete".format(order_id))
        order.delete()
        return 'success'


class PayView(Resource):
    @marshal_with(OrderResource.fields)
    def post(self, order_id):
        user_id = get_jwt_identity()
        order = Order.query.filter_by(user_id=user_id, id=order_id).first()
        if not order: abort(404, message="Order {} doesn't exist with User {}".format(user_id, order_id))
        if order.is_placed: abort(404, message="Order {} is placed, cannot pay again".format(order_id))
        args = OrderResource.validate_pay()
        if order.amount != args.money:
            abort(
                404,
                message="The amount of order {} if {}, but you pay {}, please check it agian".format(
                    order_id, order.amount, args.money
                )
            )
        order.is_placed = True
        order.update()
        return order
